package com.atguigu.tingshu.payment.service.impl;

import cn.hutool.core.util.IdUtil;
import com.atguigu.tingshu.model.payment.PaymentInfo;
import com.atguigu.tingshu.payment.config.WxPayV3Config;
import com.atguigu.tingshu.payment.service.PaymentInfoService;
import com.atguigu.tingshu.payment.service.WxPayService;
import com.atguigu.tingshu.payment.util.PayUtil;
import com.wechat.pay.java.core.RSAAutoCertificateConfig;
import com.wechat.pay.java.core.notification.NotificationConfig;
import com.wechat.pay.java.core.notification.NotificationParser;
import com.wechat.pay.java.core.notification.RequestParam;
import com.wechat.pay.java.service.payments.jsapi.JsapiServiceExtension;
import com.wechat.pay.java.service.payments.jsapi.model.*;
import com.wechat.pay.java.service.payments.model.Transaction;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class WxPayServiceImpl implements WxPayService {

    @Autowired
    private PaymentInfoService paymentInfoService;
    @Autowired
    private RSAAutoCertificateConfig config;

    @Autowired
    private WxPayV3Config wxPayV3Config;

    /**
     * 获取微信小程序拉起本地微信支付所需要参数
     *
     * @param paymentType 支付类型：支付类型：1301-订单 1302-充值
     * @param orderNo     订单编号
     * @return 小程序拉调用wx.requestPayment(Object object)需要参数
     */
    @Override
    public Map<String, String> getWxPrePayParams(String paymentType, String orderNo) {

        //保存付款记录
        PaymentInfo paymentInfo = this.paymentInfoService.savePaymentInfo(paymentType, orderNo);
        //初始化微信对接的客户端对象

        // 构建service
        JsapiServiceExtension service = new JsapiServiceExtension.Builder().config(config).build();
        // 微信下单请求对象封装
        PrepayRequest request = new PrepayRequest();
        Amount amount = new Amount();
        //单位分
        amount.setTotal(1);
        request.setAmount(amount);
        request.setAppid(wxPayV3Config.getAppid());
        request.setMchid(wxPayV3Config.getMerchantId());
        request.setDescription(paymentInfo.getContent());
        //设置异步回调路径
        request.setNotifyUrl(wxPayV3Config.getNotifyUrl());
        request.setOutTradeNo(paymentInfo.getOutTradeNo());


        //开发这资质
        Payer payer = new Payer();
        payer.setOpenid("odo3j4ujPBRopdATZnxKZ3HDOLAc");
        request.setPayer(payer);

        // 调用下单方法，得到应答
        PrepayWithRequestPaymentResponse response = service.prepayWithRequestPayment(request);
        Map<String, String> resultMap = new HashMap<>();

        if (response != null) {
            resultMap.put("timeStamp", response.getTimeStamp());
            resultMap.put("package", response.getPackageVal());
            resultMap.put("paySign", response.getPaySign());
            resultMap.put("signType", response.getSignType());
            resultMap.put("nonceStr", response.getNonceStr());
        }
        return resultMap;

    }


    /**
     * 根据商户订单编号查询交易状态
     *
     * @param orderNo
     * @return
     */
    @Override
    public Boolean queryPayStatus(String orderNo) {
		/*//1.创建查询交易请求对象
		QueryOrderByOutTradeNoRequest queryOrderByOutTradeNoRequest = new QueryOrderByOutTradeNoRequest();
		queryOrderByOutTradeNoRequest.setMchid(wxPayV3Config.getMerchantId());
		queryOrderByOutTradeNoRequest.setOutTradeNo(orderNo);

		//2.创建调用微信服务端业务对象
		JsapiServiceExtension jsapiService = new JsapiServiceExtension.Builder().config(config).build();

		//3.调用微信查询交易状态接口
		Transaction transaction = jsapiService.queryOrderByOutTradeNo(queryOrderByOutTradeNoRequest);

		//4.解析响应结果返回交易状态
		if (transaction != null) {
			Transaction.TradeStateEnum tradeState = transaction.getTradeState();
			if (Transaction.TradeStateEnum.SUCCESS == tradeState) {
				//用户支付成功
				return true;
			}
		}
		return false;*/


        //1.伪造微信交易对象
        Transaction transaction = new Transaction();
        transaction.setOutTradeNo(orderNo);
        transaction.setTransactionId("WX" + IdUtil.getSnowflakeNextId());
        //修改支付记录状态
        //	paymentInfoService.updatePaymentInfoSuccess(transaction);
        return true;
    }

    /**
     * 微信支付回调
     *
     * @param request
     * @return
     */
    @Override
    public Map<String, String> notify11(HttpServletRequest request) {
        /**
         * map.put("code", "SUCCESS");
         * map.put("message", "SUCCESS");
         */


        //从请求头中获取参数
        String wechatPaySerial = request.getHeader("Wechatpay-Serial");  //签名
        String nonce = request.getHeader("Wechatpay-Nonce");  //签名中的随机数
        String timestamp = request.getHeader("Wechatpay-Timestamp"); //时间戳
        String signature = request.getHeader("Wechatpay-Signature"); //签名类型

        //HTTP 请求体 body。切记使用原始报文，不要用 JSON 对象序列化后的字符串，避免验签的 body 和原文不一致。
        String requestBody = PayUtil.readData(request);


        // 构造 RequestParam
        RequestParam requestParam = new RequestParam.Builder()
                .serialNumber(wechatPaySerial)
                .nonce(nonce)
                .signature(signature)
                .timestamp(timestamp)
                .body(requestBody)
                .build();


        // 初始化 NotificationParser
        NotificationParser parser = new NotificationParser(config);

        //调用解析器对象解析方法 验签、解密 并转换成 Transaction
        Transaction transaction = parser.parse(requestParam, Transaction.class);
        if(transaction !=null){
            //业务验证，验证付款状态以及用户实际付款金额跟商户侧金额是否一致
            if(Transaction.TradeStateEnum.SUCCESS==transaction.getTradeState()){
                Integer payerTotal = transaction.getAmount().getPayerTotal();
                // 调试阶段支付金额为1分，后续改为动态从本地交易记录中获取实际金额
                if(payerTotal.intValue() ==1){
                    //更新本地交易记录状态
                    paymentInfoService.updatePaymentInfoSuccess(transaction);
                    Map<String, String> map = new HashMap<>();
                    map.put("code", "SUCCESS");
                    map.put("message", "SUCCESS");
                    return map;
                }
            }
        }
        return null;
    }
}
